<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>ASP.NET Core API Boxed</title>
  <link href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet" />
  <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet" />
  <style>
    .alert-close-checkbox {
      display: none;
    }
  </style>
</head>
<body>
  <div id="main" class="container body-content" role="main">

    <a href="https://github.com/Dotnet-Boxed/Templates">
      <img alt=".NET Boxed"
           class="img-responsive"
           src="https://media.githubusercontent.com/media/Dotnet-Boxed/Templates/master/Images/Banner.png"
           style="margin-bottom: 20px">
    </a>

    <section>
      <h2>ASP.NET Core API Boxed To-Do List</h2>
      <p>A short to-do list of tasks to configure your app and set it up for greater performance and security.</p>

      <article>
        <h3><span aria-hidden="true" class="fa fa-list"></span> Pre-Requisites</h3>
        <ul class="list-group">
          <li class="list-group-item">
            <input name="PreRequisites-UpdateVisualStudio" type="checkbox"> <strong>Update Visual Studio/Visual Studio Code</strong> -
            Update your version of Visual Studio or Visual Studio Code to the latest version.
          </li>
          <li class="list-group-item">
            <input name="PreRequisites-UpdateDotnetSDK" type="checkbox"> <strong>Update .NET SDK</strong> -
            Update the .NET SDK. You can download the latest version from <a href="https://dot.net">dot.net</a>.
          </li>
          <!--#if (IIS)-->
          <li class="list-group-item">
            <input name="PreRequisites-IISNETCoreWindowsServerHosting" type="checkbox"> <strong>IIS .NET Hosting Bundle</strong> -
            If you are hosting your app on IIS, install the <a href="https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/">IIS .NET Hosting Bundle</a> bundle from <a href="https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/#install-the-net-core-hosting-bundle">here</a>.
          </li>
          <!--#endif-->
        </ul>
      </article>

      <article>
        <h3><span aria-hidden="true" class="fa fa-lock"></span> API Guidelines</h3>
        <ul class="list-group">
          <li class="list-group-item">
            <input name="APIGuidelines-Microsoft" type="checkbox"> <strong>Microsoft REST API Guidelines</strong> -
            Read the <a href="https://github.com/microsoft/api-guidelines/">Microsoft REST API Guidelines</a> to learn how to write a REST API.
          </li>
          <li class="list-group-item">
            <input name="APIGuidelines-Zalando" type="checkbox"> <strong>Zalando REST'ful API Guidelines</strong> -
            Read the <a href="https://opensource.zalando.com/restful-api-guidelines/">Zalando REST'ful API Guidelines</a> to learn how to write a REST API.
          </li>
        </ul>
      </article>

      <article>
        <h3><span aria-hidden="true" class="fa fa-lock"></span> Security</h3>
        <!--#if (HttpsEverywhere)-->
        <h4>TLS over HTTPS</h4>
        <ul class="list-group">
          <li class="list-group-item">
            <input name="HTTPS-SetupTLS" type="checkbox"> <strong>Setup a TLS Certificate</strong> -
            Obtain a TLS certificate and configure it in your <em>appsettings.json</em> file. See <a href="https://docs.microsoft.com/en-us/aspnet/core/security/enforcing-ssl">this</a> for more information.
          </li>
          <li class="list-group-item">
            <input name="HTTPS-ConfigureHSTSPreload" type="checkbox"> <strong>Configure Strict Transport Security (HSTS) Preloading</strong> -
            If using Strict-Transport-Security, submit your domain to the <a href="https://hstspreload.appspot.com/">HSTS Preload</a> site so that your domain can be preloaded using HTTPS rather than HTTP See <a href="https://developer.mozilla.org/en-US/docs/Web/Security/HTTP_strict_transport_security#Preloading_Strict_Transport_Security">this</a> for more information about preloading.
          </li>
          <li class="list-group-item">
            <input name="HTTPS-TestHttps" type="checkbox"> <strong>Test Your HTTPS Implementation</strong> -
            Use the <a href="https://www.ssllabs.com/ssltest">SSLLabs.com</a> site to check that you have implemented TLS over HTTPS correctly.
          </li>
          <li class="list-group-item">
            <input name="HTTPS-CertificateTransparency" type="checkbox"> <strong>Certificate Transparency</strong> -
            <a href="https://scotthelme.co.uk/revocation-is-broken/">Certificate Transparency (CT)</a> requires that all Certificate Authorities (CA's) publically log all certificates they create. If a certificate is mistakenly issued for your site you can be notified by the following services:
            <ul>
              <li><a href="https://developers.facebook.com/tools/ct/">Facebook Certificate Transparency Monitoring</a></li>
              <li><a href="https://sslmate.com/certspotter/">sslmate CertSpotter</a></li>
              <li><a href="https://crt.sh/?q=example.com">crt.sh</a></li>
            </ul>
          </li>
        </ul>
        <!--#endif-->
        <h4>Understand Web Security</h4>
        <ul class="list-group">
          <li class="list-group-item">
            <input name="OtherSecurity-UnderstandOWASPTopTen" type="checkbox"> <strong>Understand OWASP Top 10</strong> -
            Understand the top ten security vulnerabilities and how you can protect yourself from them at <a href="https://www.owasp.org/index.php/Category:OWASP_Top_Ten_Project">OWASP Top 10</a>. Also take a look at the <a href="https://www.owasp.org/index.php/Cheat_Sheets">OWASP Top Ten Cheat Sheet</a>.
          </li>
          <li class="list-group-item">
            <input name="OtherSecurity-UnderstandCrossSiteScripting" type="checkbox"> <strong>Understand Cross Site Scripting (XSS)</strong> -
            Understand Cross Site Scripting (XSS) security vulnerabilities and how you can protect yourself from them using the <a href="https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet">OWASP XSS Cheat Sheet</a> and <a href="https://www.owasp.org/index.php/DOM_based_XSS_Prevention_Cheat_Sheet">OWASP DOM Based XSS Cheat Sheet</a>.
          </li>
          <li class="list-group-item">
            <input name="OtherSecurity-UnderstandCrossSiteRequestForgery" type="checkbox"> <strong>Understand Cross Site Request Forgery (CSRF)</strong> -
            Understand Cross Site Request Forgery security vulnerabilities and how you can protect yourself from them using the <a href="https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29_Prevention_Cheat_Sheet">OWASP CSRF Cheat Sheet</a>.
          </li>
        </ul>
        <h4>Other Security</h4>
        <ul class="list-group">
          <li class="list-group-item">
            <input name="OtherSecurity-ConfigureSecurityTxt" type="checkbox"> <strong>Configure security.txt</strong> -
            <a href="https://securitytxt.org/">Security.txt</a> is a standard which allows you to define a security policy. Edit the <em>security.txt</em> file at the root of the site. This is totally optional, you can delete this file if you want.
          </li>
          <li class="list-group-item">
            <input name="OtherSecurity-SecretStore" type="checkbox"> <strong>Use Secret Store</strong> -
            If you want to use connection strings or other secrets without checking them in to your source control repository, use the secret store. See <a href="http://go.microsoft.com/fwlink/?LinkID=532709">this</a> for more information.
          </li>
          <li class="list-group-item">
            <input name="OtherSecurity-KeepNuGetUpToDate" type="checkbox"> <strong>Keep NuGet Packages Up To Date</strong> -
            Keep your NuGet packages up to date to patch security vulnerabilities. See the section about updating below.
          </li>
          <!--#if (Azure)-->
          <li class="list-group-item">
            <input name="OtherSecurity-AzureSQLThreatDetection" type="checkbox"> <strong>Turn on Azure SQL Database Threat Detection</strong> -
            If you are using SQL Database on Azure, then turn on <a href="https://azure.microsoft.com/en-us/documentation/articles/sql-database-threat-detection-get-started/">Threat Detection</a>.
          </li>
          <!--#endif-->
        </ul>
      </article>

      <article>
        <h3><span aria-hidden="true" class="fa fa-tachometer"></span> Performance</h3>
        <h4>Content Delivery Networks (CDN)</h4>
        <ul class="list-group">
          <li class="list-group-item">
            <input name="ContentDeliveryNetworks-UploadStaticFilesToCDN" type="checkbox"> <strong>Use a CDN</strong> -
            Point a <a href="http://en.wikipedia.org/wiki/Content_delivery_network">CDN</a> to your API for vastly better performance.
            <ul>
              <li><a href="http://www.cloudflare.com">Cloudflare CDN</a></li>
              <li><a href="http://azure.microsoft.com/en-us/documentation/articles/cdn-serve-content-from-cdn-in-your-web-application/">Azure CDN</a></li>
            </ul>
          </li>
        </ul>
        <h4>Caching</h4>
        <ul class="list-group">
          <li class="list-group-item">
            <input name="Caching-ConfigureCaching" type="checkbox"> <strong>Configure Caching</strong> -
            Some resources are generated at runtime and then cached for a certain time period.
            If these resources won't change much on your site, change the length of time they are cached. Open the <em>appsettings.json</em> file and take a look at the cache profiles section.
          </li>
          <li class="list-group-item">
            <input name="Caching-AddMoreCaching" type="checkbox"> <strong>Add More Caching</strong> -
            Use the <code>[ResponseCache]</code> attribute in conjunction with the cache profiles section in the <em>appsettings.json</em> file to cache pages that don't change often and do not contain sensitive information. See
            <a href="http://www.asp.net/mvc/overview/older-versions-1/controllers-and-routing/improving-performance-with-output-caching-cs">this</a> for more information.
          </li>
        </ul>
        <h4>Benchmarking</h4>
        <ul class="list-group">
          <li class="list-group-item">
            <input name="OtherPerformance-GoogleLighthouse" type="checkbox"> <strong>Run Google Lighthouse</strong> -
            Use <a href="https://developers.google.com/web/tools/lighthouse/">Google Lighthouse</a> to benchmark your sites performance and to get suggestions on how to further improve performance.
          </li>
          <li class="list-group-item">
            <input name="OtherPerformance-Webhint" type="checkbox"> <strong>Run Webhint</strong> -
            Use <a href="https://webhint.io/">Webhint</a> to benchmark your sites performance and to get suggestions on how to further improve performance.
          </li>
        </ul>
        <h4>Other Performance</h4>
        <ul class="list-group">
          <li class="list-group-item">
            <input name="OtherPerformance-Prefetcher" type="checkbox"> <strong>Enable Windows Server Pre-fetcher</strong> -
            This is only relevant if your site is hosted on Windows Server. You can enable the <a href="http://en.wikipedia.org/wiki/Prefetcher">pre-fetcher</a> to get a performance and reduce the disk-read cost of application start-up. Click <a href="http://www.asp.net/aspnet/overview/aspnet-and-visual-studio-2012/whats-new#_Toc_perf_6">here</a> for more information on how to do this.
          </li>
        </ul>
      </article>

      <!--#if (ApplicationInsights)-->
      <article>
        <h3><span aria-hidden="true" class="fa fa-exclamation-triangle"></span> Resilience and Error Handling</h3>
        <ul class="list-group">
          <li class="list-group-item">
            <input name="ResilienceAndErrorHandling-ApplicationInsights" type="checkbox"> <strong>Application Insights</strong> -
            Application Insights helps monitor your site and know about it when it goes down. Login to <a href="http://azure.microsoft.com">Azure</a>, create a new Application Insights instance, retrieve the Instrumentation Key and add it to your <em>appsettings.json</em> file. For more information see the <a href="http://docs.asp.net/en/latest/fundamentals/application-insights.html">Getting Started</a> guide.
          </li>
        </ul>
      </article>
      <!--#endif-->

      <article>
        <h3><span aria-hidden="true" class="fa fa-users"></span> Thank Developers</h3>
        <ul class="list-group">
          <li class="list-group-item">
            <input name="ThankDevelopers-ConfigureHumansTxt" type="checkbox"> <strong>Configure humans.txt</strong> -
            <a href="http://humanstxt.org/">Humans.txt</a> is a standard way of describing and thanking the people that built your app. Edit the <em>humans.txt</em> file at the root of the app. This is totally optional, you can delete this file if you want.
            Be careful what you put into this file, you could give away clues about potential attack vectors on your site.
            Even giving contact details can be an attack vector (Most hackers manipulate people to get access).
          </li>
          <li class="list-group-item">
            <input name="ThankDevelopers-Review" type="checkbox"> <strong>Thank Developers</strong> -
            A lot of work was put into this project template. Show your appreciation by giving the project a star on <a href="https://github.com/Dotnet-Boxed/Templates">GitHub</a>.
          </li>
        </ul>
      </article>

      <article>
        <h3><span aria-hidden="true" class="fa fa-refresh"></span> Keeping Your Site Up To Date</h3>
        <ul class="list-group">
          <li class="list-group-item">
            <input name="KeepingYourSiteUpToDate-KeepNuGetPackagesUpToDate" type="checkbox"> <strong>Keep NuGet Packages Up To Date</strong> -
            Most updates can be easily carried out by simply updating <a href="https://www.nuget.org/">NuGet</a> packages. See <a href="https://docs.nuget.org/consume/package-manager-dialog">this</a> link for more information.
          </li>
          <li class="list-group-item">
            <input name="KeepingYourSiteUpToDate-KeepTemplateUpToDate" type="checkbox"> <strong>Keep Template Up To Date</strong> -
            Keep an eye on the <a href="https://github.com/Dotnet-Boxed/Templates/releases">release notes</a> and update your site accordingly.
          </li>
        </ul>
      </article>

    </section>

  </div>

  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
  <script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.1/bootstrap.min.js"></script>
  <script>
    // https://github.com/jeremydurham/persist-js
    (function () {
      if (window.google && google.gears) { return; }
      var F = null; if (typeof GearsFactory != 'undefined') { F = new GearsFactory(); } else { try { F = new ActiveXObject('Gears.Factory'); if (F.getBuildInfo().indexOf('ie_mobile') != -1) { F.privateSetGlobalObject(this); } } catch (e) { if ((typeof navigator.mimeTypes != 'undefined') && navigator.mimeTypes["application/x-googlegears"]) { F = document.createElement("object"); F.style.display = "none"; F.width = 0; F.height = 0; F.type = "application/x-googlegears"; document.documentElement.appendChild(F); } } }
      if (!F) { return; }
      if (!window.google) { google = {}; }
      if (!google.gears) { google.gears = { factory: F }; }
    })(); Persist = (function () {
      var VERSION = '0.3.1', P, B, esc, init, empty, ec; ec = (function () {
        var EPOCH = 'Thu, 01-Jan-1970 00:00:01 GMT', RATIO = 1000 * 60 * 60 * 24, KEYS = ['expires', 'path', 'domain'], esc = escape, un = unescape, doc = document, me; var get_now = function () { var r = new Date(); r.setTime(r.getTime()); return r; }; var cookify = function (c_key, c_val) {
          var i, key, val, r = [], opt = (arguments.length > 2) ? arguments[2] : {}; r.push(esc(c_key) + '=' + esc(c_val)); for (var idx = 0; idx < KEYS.length; idx++) { key = KEYS[idx]; val = opt[key]; if (val) { r.push(key + '=' + val); } }
          if (opt.secure) { r.push('secure'); }
          return r.join('; ');
        }; var alive = function () { var k = '__EC_TEST__', v = new Date(); v = v.toGMTString(); this.set(k, v); this.enabled = (this.remove(k) == v); return this.enabled; }; me = {
          set: function (key, val) {
            var opt = (arguments.length > 2) ? arguments[2] : {}, now = get_now(), expire_at, cfg = {}; if (opt.expires) {
              if (opt.expires == -1) { cfg.expires = -1 }
              else { var expires = opt.expires * RATIO; cfg.expires = new Date(now.getTime() + expires); cfg.expires = cfg.expires.toGMTString(); }
            }
            var keys = ['path', 'domain', 'secure']; for (var i = 0; i < keys.length; i++) { if (opt[keys[i]]) { cfg[keys[i]] = opt[keys[i]]; } }
            var r = cookify(key, val, cfg); doc.cookie = r; return val;
          }, has: function (key) { key = esc(key); var c = doc.cookie, ofs = c.indexOf(key + '='), len = ofs + key.length + 1, sub = c.substring(0, key.length); return ((!ofs && key != sub) || ofs < 0) ? false : true; }, get: function (key) {
            key = esc(key); var c = doc.cookie, ofs = c.indexOf(key + '='), len = ofs + key.length + 1, sub = c.substring(0, key.length), end; if ((!ofs && key != sub) || ofs < 0) { return null; }
            end = c.indexOf(';', len); if (end < 0) { end = c.length; }
            return un(c.substring(len, end));
          }, remove: function (k) { var r = me.get(k), opt = { expires: EPOCH }; doc.cookie = cookify(k, '', opt); return r; }, keys: function () {
            var c = doc.cookie, ps = c.split('; '), i, p, r = []; for (var idx = 0; idx < ps.length; idx++) { p = ps[idx].split('='); r.push(un(p[0])); }
            return r;
          }, all: function () {
            var c = doc.cookie, ps = c.split('; '), i, p, r = []; for (var idx = 0; idx < ps.length; idx++) { p = ps[idx].split('='); r.push([un(p[0]), un(p[1])]); }
            return r;
          }, version: '0.2.1', enabled: false
        }; me.enabled = alive.call(me); return me;
      }()); var index_of = (function () {
        if (Array.prototype.indexOf) { return function (ary, val) { return Array.prototype.indexOf.call(ary, val); }; } else {
          return function (ary, val) {
            var i, l; for (var idx = 0, len = ary.length; idx < len; idx++) { if (ary[idx] == val) { return idx; } }
            return -1;
          };
        }
      })(); empty = function () { }; esc = function (str) { return 'PS' + str.replace(/_/g, '__').replace(/ /g, '_s'); }; var C = { search_order: ['localstorage', 'globalstorage', 'gears', 'cookie', 'ie', 'flash'], name_re: /^[a-z][a-z0-9_ \-]+$/i, methods: ['init', 'get', 'set', 'remove', 'load', 'save', 'iterate'], sql: { version: '1', create: "CREATE TABLE IF NOT EXISTS persist_data (k TEXT UNIQUE NOT NULL PRIMARY KEY, v TEXT NOT NULL)", get: "SELECT v FROM persist_data WHERE k = ?", set: "INSERT INTO persist_data(k, v) VALUES (?, ?)", remove: "DELETE FROM persist_data WHERE k = ?", keys: "SELECT * FROM persist_data" }, flash: { div_id: '_persist_flash_wrap', id: '_persist_flash', path: 'persist.swf', size: { w: 1, h: 1 }, params: { autostart: true } } }; B = {
        gears: {
          size: -1, test: function () { return (window.google && window.google.gears) ? true : false; }, methods: {
            init: function () { var db; db = this.db = google.gears.factory.create('beta.database'); db.open(esc(this.name)); db.execute(C.sql.create).close(); }, get: function (key) { var r, sql = C.sql.get; var db = this.db; var ret; db.execute('BEGIN').close(); r = db.execute(sql, [key]); ret = r.isValidRow() ? r.field(0) : null; r.close(); db.execute('COMMIT').close(); return ret; }, set: function (key, val) { var rm_sql = C.sql.remove, sql = C.sql.set, r; var db = this.db; var ret; db.execute('BEGIN').close(); db.execute(rm_sql, [key]).close(); db.execute(sql, [key, val]).close(); db.execute('COMMIT').close(); return val; }, remove: function (key) { var get_sql = C.sql.get, sql = C.sql.remove, r, val = null, is_valid = false; var db = this.db; db.execute('BEGIN').close(); db.execute(sql, [key]).close(); db.execute('COMMIT').close(); return true; }, iterate: function (fn, scope) {
              var key_sql = C.sql.keys; var r; var db = this.db; r = db.execute(key_sql); while (r.isValidRow()) { fn.call(scope || this, r.field(0), r.field(1)); r.next(); }
              r.close();
            }
          }
        }, globalstorage: {
          size: 5 * 1024 * 1024, test: function () {
            if (window.globalStorage) {
              var domain = '127.0.0.1'; if (this.o && this.o.domain) { domain = this.o.domain; }
              try { var dontcare = globalStorage[domain]; return true; } catch (e) {
                if (window.console && window.console.warn) { console.warn("globalStorage exists, but couldn't use it because your browser is running on domain:", domain); }
                return false;
              }
            } else { return false; }
          }, methods: { key: function (key) { return esc(this.name) + esc(key); }, init: function () { this.store = globalStorage[this.o.domain]; }, get: function (key) { key = this.key(key); return this.store.getItem(key); }, set: function (key, val) { key = this.key(key); this.store.setItem(key, val); return val; }, remove: function (key) { var val; key = this.key(key); val = this.store.getItem[key]; this.store.removeItem(key); return val; } }
        }, localstorage: {
          size: -1, test: function () {
            try {
              if (window.localStorage && window.localStorage.setItem("test", null) == undefined) {
                if (/Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent)) {
                  var ffVersion = RegExp.$1; if (ffVersion >= 9) { return true; }
                  if (window.location.protocol == 'file:') { return false; }
                } else { return true; }
              } else { return false; }
              return window.localStorage ? true : false;
            } catch (e) { return false; }
          }, methods: { key: function (key) { return this.name + '>' + key; }, init: function () { this.store = localStorage; }, get: function (key) { key = this.key(key); return this.store.getItem(key); }, set: function (key, val) { key = this.key(key); this.store.setItem(key, val); return val; }, remove: function (key) { var val; key = this.key(key); val = this.store.getItem(key); this.store.removeItem(key); return val; }, iterate: function (fn, scope) { var l = this.store, key, keys; for (var i = 0; i < l.length; i++) { key = l.key(i); keys = key.split('>'); if ((keys.length == 2) && (keys[0] == this.name)) { fn.call(scope || this, keys[1], l.getItem(key)); } } } }
        }, ie: {
          prefix: '_persist_data-', size: 64 * 1024, test: function () { return window.ActiveXObject ? true : false; }, make_userdata: function (id) { var el = document.createElement('div'); el.id = id; el.style.display = 'none'; el.addBehavior('#default#userdata'); document.body.appendChild(el); return el; }, methods: {
            init: function () { var id = B.ie.prefix + esc(this.name); this.el = B.ie.make_userdata(id); if (this.o.defer) { this.load(); } }, get: function (key) {
              var val; key = esc(key); if (!this.o.defer) { this.load(); }
              val = this.el.getAttribute(key); return val;
            }, set: function (key, val) {
              key = esc(key); this.el.setAttribute(key, val); if (!this.o.defer) { this.save(); }
              return val;
            }, remove: function (key) {
              var val; key = esc(key); if (!this.o.defer) { this.load(); }
              val = this.el.getAttribute(key); this.el.removeAttribute(key); if (!this.o.defer) { this.save(); }
              return val;
            }, load: function () { this.el.load(esc(this.name)); }, save: function () { this.el.save(esc(this.name)); }
          }
        }, cookie: { delim: ':', size: 4000, test: function () { return P.Cookie.enabled ? true : false; }, methods: { key: function (key) { return this.name + B.cookie.delim + key; }, get: function (key, fn) { var val; key = this.key(key); val = ec.get(key); return val; }, set: function (key, val, fn) { key = this.key(key); ec.set(key, val, this.o); return val; }, remove: function (key, val) { var val; key = this.key(key); val = ec.remove(key); return val; } } }, flash: {
          test: function () {
            try { if (!swfobject) { return false; } } catch (e) { return false; }
            var major = swfobject.getFlashPlayerVersion().major; return (major >= 8) ? true : false;
          }, methods: {
            init: function () {
              if (!B.flash.el) { var key, el, fel, cfg = C.flash; el = document.createElement('div'); el.id = cfg.div_id; fel = document.createElement('div'); fel.id = cfg.id; el.appendChild(fel); document.body.appendChild(el); B.flash.el = swfobject.createSWF({ id: cfg.id, data: this.o.swf_path || cfg.path, width: cfg.size.w, height: cfg.size.h }, cfg.params, cfg.id); }
              this.el = B.flash.el;
            }, get: function (key) { var val; key = esc(key); val = this.el.get(this.name, key); return val; }, set: function (key, val) { var old_val; key = esc(key); old_val = this.el.set(this.name, key, val); return old_val; }, remove: function (key) { var val; key = esc(key); val = this.el.remove(this.name, key); return val; }
          }
        }
      }; init = function () {
        var i, l, b, key, fns = C.methods, keys = C.search_order; for (var idx = 0, len = fns.length; idx < len; idx++) { P.Store.prototype[fns[idx]] = empty; }
        P.type = null; P.size = -1; for (var idx2 = 0, len2 = keys.length; !P.type && idx2 < len2; idx2++) { b = B[keys[idx2]]; if (b.test()) { P.type = keys[idx2]; P.size = b.size; for (key in b.methods) { P.Store.prototype[key] = b.methods[key]; } } }
        P._init = true;
      }; P = {
        VERSION: VERSION, type: null, size: 0, add: function (o) { B[o.id] = o; C.search_order = [o.id].concat(C.search_order); init(); }, remove: function (id) {
          var ofs = index_of(C.search_order, id); if (ofs < 0) { return; }
          C.search_order.splice(ofs, 1); delete B[id]; init();
        }, Cookie: ec, Store: function (name, o) {
          if (!C.name_re.exec(name)) { throw new Error("Invalid name"); }
          if (!P.type) { throw new Error("No suitable storage found"); }
          o = o || {}; this.name = name; o.domain = o.domain || location.hostname || 'localhost'; o.domain = o.domain.replace(/:\d+$/, ''); o.domain = (o.domain == 'localhost') ? '' : o.domain; this.o = o; o.expires = o.expires || 365 * 2; o.path = o.path || '/'; if (this.o.search_order) { C.search_order = this.o.search_order; init(); }
          this.init();
        }
      }; init(); return P;
    })();
  </script>
  <script>
    $(function () {
      var store = new Persist.Store('ASP NET Core API Boxed ReadMe');

      function turnOn($checkbox) {
        if ($checkbox.hasClass('alert-close-checkbox')) {
          $checkbox.parent().hide();
        }
        else {
          $checkbox.parent().addClass('list-group-item-success');
        }
      }

      function turnOff($checkbox) {
        if ($checkbox.hasClass('alert-close-checkbox')) {
          $checkbox.parent().show();
        }
        else {
          $checkbox.parent().removeClass('list-group-item-success');
        }
      }

      $(':checkbox').click(function () {
        var name = this.name;
        var value = this.value;

        if ($(this).is(':checked')) {
          store.set(this.name, 'checked');
          turnOn($(this));
        } else {
          store.remove(this.name);
          turnOff($(this));
        }
      });

      $(':checkbox').each(function () {
        var isChecked = store.get(this.name) == 'checked';
        $(this).prop('checked', isChecked);
        if (isChecked) {
          turnOn($(this));
        }
        else {
          turnOff($(this));
        }
      });
    })
  </script>
</body>
</html>
